#!/usr/bin/env python
#-*- coding: utf8 -*-

"""

 Copyright by Andrea Mistrali <am@am.cx>
 First version: 2011-06-16T15:08 CEST (+0200)

 Synopsis: QB Mail Shell

 $Id: qbmsh.py 450 2012-04-13 12:35:55Z andre $

"""

import cmd
import readline
import os, sys
import pwd, getpass

from cubemail import meta, model
from sqlalchemy.orm import joinedload


__version__ ='1.0'
__id__ = '$Revision: 450 $'
__author__ ='$Author: andre $'

TEMPLATES={
'aliases': """\
Alias: %(left_part)s
Domain: %(domain)s

User: %(user)s
Extension: %(extension)s

Redirect to: %(redirect_to)s
""",

'users': """\
Username: %(username)s
Password: %(password)s
  Schema: %(schema)s
    Mail: %(mail)s

    Name: %(name)s
 Surname: %(surname)s

  Domain: %(domain)s
     UID: %(uid)d
     GID: %(gid)d

 IMAP ok: %(imap_ok)s
 POP3 ok: %(imap_ok)s

  Master: %(is_master_user)s
Ext.Auth: %(external_auth)s
""",

'domain': """\
Domain name: %(name)s
    Aliases: %(domain_aliases)s

   Base UID: %(base_uid)s
   Base dir: %(base_dir)s

  Transport: %(transport)s
Bkp Transp.: %(backup_transport)s

      Quota: %(quota)s
     Public: %(publicns)s
"""
}


class Command(object):

    def __init__(self):
        self.shelluser=getpass.getuser()
        self.shell=pwd.getpwnam(self.shelluser).pw_shell
        self.cli=CLI(self)

    def _s2s(self, mask):
        """
        star2sql
        Convert a * to % and an empty string to % too
        """
        if mask=='': return '%'
        return mask.replace('*', '%')

    def domain(self, d):
        q=meta.session.query(model.cmDomain).options(joinedload('primary_domain'), joinedload('domain_aliases')).filter(model.cmDomain.name==d).first()
        if not q:
            print "no such domain '%s'" % d
        elif q.isPrimary():
            return q
        else:
            print "redirecting to primary domain '%s'" % q.primary_domain
            q2=meta.session.query(model.cmDomain).options(joinedload('primary_domain'), joinedload('domain_aliases')).filter(model.cmDomain.name==q.primary_domain.name).first()
            return q2

    def domains(self, mask='*'):
        mask=self._s2s(mask)
        return meta.session.query(model.cmDomain).filter(model.cmDomain.name.like(mask)).\
                order_by(model.cmDomain.name).all()

    def user(self, u):
        q=meta.session.query(model.cmUser).filter(model.cmUser.username==u).\
                filter(model.cmUser.domain==self.cli.getpath('domain')).first()
        if not q: print "no such user '%s'" % u
        return q

    def users(self, mask='*'):
        if self.cli._path['domain']:
            mask=self._s2s(mask)
            return meta.session.query(model.cmUser).filter(model.cmUser.username.like(mask)).\
                    filter(model.cmUser.domain==self.cli.getpath('domain')).\
                    order_by(model.cmUser.username).all()

    def alias(self, a):
        q=meta.session.query(model.cmAlias).options(joinedload('user')).filter(model.cmAlias.left_part==a).\
                filter(model.cmAlias.domain==self.cli.getpath('domain')).first()
        if not q: print "no such alias '%s'" % a
        return q

    def aliases(self, mask='*'):
        if self.cli._path['domain']:
            mask=self._s2s(mask)
            return meta.session.query(model.cmAlias).filter(model.cmAlias.left_part.like(mask)).\
                    filter(model.cmAlias.domain==self.cli.getpath('domain')).\
                    order_by(model.cmAlias.left_part).all()

class CLI(cmd.Cmd):
  
    def __init__(self, command):
        cmd.Cmd.__init__(self)
        self.cmd=command
        self.intro="\nQB Mail Shell v. %s\nDB: %s@%s [sqlecho %s]\nRunning as user '%s'\n" % (__version__, 
                meta.engine.url.database, meta.engine.url.host,
                ['off', 'on'][meta.engine.echo == True],
                self.cmd.shelluser)
        self._path = { 'domain': None,
                'level': None,
                'object': None }
        self.setprompt()

    # PATH Management
    def setpath(self, o):

        if o=='..':
            self._path[self.pathlevel]=None
            return

        if self._path['object']:
            return
        if self._path['level']:
            if self._path['level']=='users':
                self._path['object']=self.cmd.user(o)
            elif self._path['level']=='aliases':
                self._path['object']=self.cmd.alias(o)
        elif self._path['domain']:
            if o in ['users', 'aliases']:
                self._path['level']=o
            else:
                print "no such level '%s'" % o
        elif not self._path['domain']:
            self._path['domain']=self.cmd.domain(o)

    def getpath(self, o=None):
        if o:
            return self._path[o]
        else:
            return self._path['object'] or self._path['level'] or self._path['domain'] or None

    def haspath(self, o):
        return not ( self._path[o] == None)

    @property
    def pathlevel(self):
        for k in ['object', 'level', 'domain']:
            if self._path[k]:
                return k
        return None

    # Misc
    def setprompt(self):
        self.prompt="\033[37;1mQM %s> \033[0;0m" % '/'.join(['%s' % self.getpath(x) for x in ('domain', 'level', 'object') if self.haspath(x)])

    def emptyline(self): pass
    def postcmd(self, stop, line): self.setprompt()

    # Help
    def help_help(self): print "Non hypertextual help system. type 'help <topic>' to see help on <topic>"
    def help_quit(self): print "Exit, forgetting changes - Sayonara!"
    help_EOF = help_quit
    def help_exit(self): print "Exit, saving changes & bye bye"
    def help_shell(self): print "Execute a shell command or spawn a shell if no command is given.\nTo exit interactive shell type 'exit'.\n'!' is a (shorter) synonym"
    def help_version(self): print "Show version"
    help_ver = help_version
    def help_clear(self): print "Clear screen. Typing Ctrl-L is usually faster."
    help_cls = help_clear
    def help_cd(self): print "Select level to work on"
    def help_ls(self): print "Show actual level contents"
    def help_show(self): print "Show actual object"

    # Commands
    def do_quit(self, args):
        print "Sayonara!"
        sys.exit(1)

    def do_EOF(self, args):
        print
        self.do_quit(args)


    def do_exit(self, args):
        print "Bye, bye"
        sys.exit(0)

    def do_version(self, args):
        print "QB Mail Shell ver. %s %s" % (__version__, __id__)
    do_ver = do_version

    def do_clear(self, args):
        print "\033[2J\033[0;0H"
    do_cls = do_clear

    def do_sqlecho(self, args):
        st={'on': True, 'off': False}
        if st.has_key(args.lower()):
            meta.engine.echo=st[args.lower()]
        print "SQL echo",['off', 'on'][meta.engine.echo==True]

    def do_shell(self, args):
        if args:
            os.system(args)
        else:
            print "Spawning shell %s, type 'exit' to return" % self.cmd.shell
            os.system(self.cmd.shell)

    # Interactive
    def _print_levels(self):
        print "users/\naliases/"

    def do_path(self, args):
        print self._path, "level:", self.pathlevel

    def do_ls(self, args):
        if not self.pathlevel:
            for d in self.cmd.domains(args):
                if d.isPrimary():
                    print d
                else:
                    print d,"->",d.primary_domain
        elif self.pathlevel=='domain':
            self._print_levels()
        elif self.pathlevel=='level':
            if self.getpath() == 'users':
                for u in self.cmd.users():
                    print u.username
            elif self.getpath() == 'aliases':
                for a in self.cmd.aliases():
                    print a

    def do_show(self, args):
        if self.pathlevel == 'object':
            print TEMPLATES[self.getpath('level')] % self.getpath('object').__dict__
        if self.pathlevel == 'domain':
            print TEMPLATES['domain'] % self.getpath('domain').__dict__

    def do_cd(self, args):
        self.setpath(args)





def main():
    command=Command()
    command.cli.cmdloop(command.cli.intro)

# If we have been called as 'python <script>' let's call main function
if __name__ == "__main__":
  main()

